package com.zb.service;

import com.alibaba.fastjson.JSON;
import com.zb.entity.TbSkuModel;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.*;

/**
 * <p>添加描述信息</p>
 *
 * @author 李柯
 * @since 2022年11月04日 16:44
 */
@Service
public class SearchService {

    @Autowired
    public RestHighLevelClient client;

    public Map<String,Object>search(Map<String,String>param)throws Exception{
        Map<String, Object> data = new HashMap<>();
        String keyword = param.get("keyword");
        if (StringUtils.isEmpty(keyword)) {
            keyword = "华为";
        }
        Integer start = (Integer.valueOf(param.get("index")) - 1) * Integer.valueOf(param.get("size"));
        Integer size = Integer.valueOf(param.get("size"));

        SearchRequest searchRequest = new SearchRequest("tb_sku");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.from(start);
        searchSourceBuilder.size(size);

        //分组查询
        searchSourceBuilder.aggregation(AggregationBuilders.terms("brandGroup").field("brand_name").size(50));
        searchSourceBuilder.aggregation(AggregationBuilders.terms("cateGroup").field("category_name").size(50));
        searchSourceBuilder.aggregation(AggregationBuilders.terms("specGroup").field("spec").size(50));

        //多条件查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, "name");
        boolQuery.must(multiMatchQueryBuilder);

        if (!StringUtils.isEmpty(param.get("brand"))) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brand_name", param.get("brand"));
            boolQuery.filter(termQueryBuilder);
        }

        if (!StringUtils.isEmpty(param.get("category"))) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("category_name", param.get("category"));
            boolQuery.filter(termQueryBuilder);
        }
        for (String key : param.keySet()) {
            if (key.startsWith("spec_")) {
                String esKey = key.substring(5);    //截取spec_尺寸 获取尺寸
                String esVal = param.get(key);   //根据spec_尺寸 获取17英寸值
                TermQueryBuilder termQuery = QueryBuilders.termQuery("specMap." + esKey + ".keyword", esVal);
                boolQuery.filter(termQuery);
            }
        }
        if (!StringUtils.isEmpty(param.get("price"))) {
            String[] prices = param.get("price").split("-");
            RangeQueryBuilder priceRange = null;
            System.out.println(Arrays.toString(prices));
            if (prices[1].equals("*")) {
                System.out.println("1");
                priceRange = QueryBuilders.rangeQuery("price").gte(prices[0]);
            } else {
                System.out.println("2");
                priceRange = QueryBuilders.rangeQuery("price").gte(prices[0]).lte(prices[1]);
            }
            boolQuery.filter(priceRange);
        }

        searchSourceBuilder.query(boolQuery);


        //设置排序操作
        if (!StringUtils.isEmpty(param.get("sortFeild"))
                && !StringUtils.isEmpty(param.get("sortRule"))){
            String sortFeild =param.get("sortFeild");
            String sortRule =param.get("sortRule");
            FieldSortBuilder fieldSortBuilder = new FieldSortBuilder(sortFeild).order(sortRule.equals("asc") ? SortOrder.ASC : SortOrder.DESC);
            searchSourceBuilder.sort(fieldSortBuilder);
        }

        //设置高亮对象
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<span style='color:red;'>");
        highlightBuilder.postTags("</span>");
        highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
        searchSourceBuilder.highlighter(highlightBuilder);

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        //获取分组
        Terms brandTerm = searchResponse.getAggregations().get("brandGroup");
        List<String> brandList = this.termAsList(brandTerm);
        Terms cateTerm = searchResponse.getAggregations().get("cateGroup");
        List<String> cateList = this.termAsList(cateTerm);
        Terms specTerm = searchResponse.getAggregations().get("specGroup");
        Map<String, Set> specMap = this.termAsMap(specTerm);
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();

        List<TbSkuModel> skuModels = new ArrayList<>();
        for (SearchHit hit : searchHits) {
            String id = hit.getId();
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            String json = JSON.toJSONString(sourceAsMap);
            TbSkuModel skuModel = JSON.parseObject(json, TbSkuModel.class);
            skuModel.setId(id);
            Map<String, HighlightField> highlightFieldMap = hit.getHighlightFields();
            //获取name的高亮数据
            if (highlightFieldMap!=null){
                HighlightField nameHf = highlightFieldMap.get("name");
                if (nameHf!=null){
                    Text[] nameHfFragments = nameHf.getFragments();
                    StringBuffer sbf = new StringBuffer();
                    for (Text text : nameHfFragments) {
                        sbf.append(text.toString());
                    }
                    skuModel.setName(sbf.toString());
                }
            }
            skuModels.add(skuModel);
        }
        data.put("skuModels", skuModels);
        data.put("brandList", brandList);
        data.put("cateList", cateList);
        data.put("specMap", specMap);
        return data;
    }

    public Map<String, Set> termAsMap(Terms terms) {
        Map<String, Set> map = new HashMap<>();
        List<String> list = this.termAsList(terms);
        for (String json : list) {
            //json = {'颜色': '红色', '版本': '4GB+64GB'}
            Map<String, String> jsonMap = JSON.parseObject(json, Map.class);
            //map.put("颜色","红色");
            //map.put("版本","4GB+64GB");
            for (Map.Entry<String, String> entry : jsonMap.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                Set valueSet = map.get(key);    //检查key在map中是否存在
                if (valueSet == null) {         //如果不存在就是第一次添加信息,
                    valueSet = new HashSet();
                }
                valueSet.add(value);
                map.put(key, valueSet);
            }

        }

        return map;
    }


    private List<String> termAsList(Terms terms) {
        List<String> list = new ArrayList<>();
        for (Terms.Bucket bucket : terms.getBuckets()) {
            list.add(bucket.getKeyAsString());
        }

        return list;
    }

    /**
     * 建文档
     * @throws Exception
     */
    public void createIndex() throws Exception{
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("tb_sku");
        createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0").build());
        createIndexRequest.mapping("doc", "{\n" +
                "\t\"properties\": {\n" +
                "\t\t\"sn\": {\n" +
                "\t\t\t\"type\": \"text\"\n" +
                "\t\t},\n" +
                "\t\t\"name\": {\n" +
                "\t\t\t\"type\": \"text\",\n" +
                "\t\t\t\"analyzer\": \"ik_max_word\",\n" +
                "\t\t\t\"search_analyzer\": \"ik_smart\"\n" +
                "\t\t},\n" +
                "\t\t\"price\": {\n" +
                "\t\t\t\"type\": \"float\"\n" +
                "\t\t},\n" +
                "\t\t\"num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"alert_num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"image\": {\n" +
                "\t\t\t\"type\": \"text\"\n" +
                "\t\t},\n" +
                "\t\t\"images\": {\n" +
                "\t\t\t\"type\": \"text\"\n" +
                "\t\t},\n" +
                "\t\t\"weight\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"create_time\": {\n" +
                "\t\t\t\"type\": \"date\",\n" +
                "\t\t\t\"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd\"\n" +
                "\t\t},\n" +
                "\t\t\"update_time\": {\n" +
                "\t\t\t\"type\": \"date\",\n" +
                "\t\t\t\"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd\"\n" +
                "\t\t},\n" +
                "\t\t\"spu_id\": {\n" +
                "\t\t\t\"type\": \"text\"\n" +
                "\t\t},\n" +
                "\t\t\"category_id\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"category_name\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"brand_name\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"spec\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"sale_num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"comment_num\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"status\": {\n" +
                "\t\t\t\"type\": \"keyword\"\n" +
                "\t\t},\n" +
                "\t\t\"version\": {\n" +
                "\t\t\t\"type\": \"integer\"\n" +
                "\t\t},\n" +
                "\t\t\"specMap\":{\n" +
                "               \"properties\":{\n" +
                "                   \"test\":{\n" +
                "                       \"type\": \"keyword\"\n" +
                "}\n" +
                "}\n" +
                "\t\t}\n" +
                "\t}\n" +
                "}", XContentType.JSON);
        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse.isAcknowledged());
    }

    public void importData() throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shop_goods?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8", "root", "root");
        PreparedStatement pstm = con.prepareStatement("select * from tb_sku");
        ResultSet rs=pstm.executeQuery();
        while (rs.next()) {
            Map<String, Object> jsonMap = new HashMap<>();
            jsonMap.put("sn", rs.getString("sn"));
            jsonMap.put("name", rs.getString("name"));
            jsonMap.put("price", rs.getFloat("price"));
            jsonMap.put("num", rs.getInt("num"));
            jsonMap.put("alert_num", rs.getInt("alert_num"));
            jsonMap.put("image", rs.getString("image"));
            jsonMap.put("images", rs.getString("images"));
            jsonMap.put("weight", rs.getInt("weight"));
            jsonMap.put("spu_id", rs.getString("spu_id"));
            jsonMap.put("category_id", rs.getInt("category_id"));
            jsonMap.put("category_name", rs.getString("category_name"));
            jsonMap.put("brand_name", rs.getString("brand_name"));
            jsonMap.put("create_time", rs.getDate("create_time").toString());
            jsonMap.put("update_time", rs.getDate("update_time").toString());
            jsonMap.put("spec", rs.getString("spec"));
            jsonMap.put("sale_num", rs.getInt("sale_num"));
            jsonMap.put("comment_num", rs.getInt("comment_num"));
            jsonMap.put("status", rs.getString("status"));
            jsonMap.put("version", rs.getInt("version"));
            Map map = JSON.parseObject(rs.getString("spec"), Map.class);
            jsonMap.put("specMap", map);
            IndexRequest indexRequest = new IndexRequest("tb_sku", "doc", rs.getString("id"));
            indexRequest.source(jsonMap);
            IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(response.status());
        }
    }
}
